package org.robotlegs.xxl.mvcs 
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.system.ApplicationDomain;
	import org.osflash.signals.ISignal;
	
	import org.osflash.signals.natives.sets.DisplayObjectSignalSet;
	import org.robotlegs.adapters.SwiftSuspendersInjector;
	import org.robotlegs.adapters.SwiftSuspendersReflector;
	import org.robotlegs.base.ContextError;
	import org.robotlegs.core.IInjector;
	import org.robotlegs.core.IMediatorMap;
	import org.robotlegs.core.IReflector;
	import org.robotlegs.core.IViewMap;
	import org.robotlegs.xxl.base.ContextBase;
	import org.robotlegs.xxl.base.ContextSignal;
	import org.robotlegs.xxl.base.MediatorMap;
	import org.robotlegs.xxl.base.SignalCommandMap;
	import org.robotlegs.xxl.base.SignalMap;
	import org.robotlegs.xxl.base.ViewMap;
	import org.robotlegs.xxl.core.IContext;
	import org.robotlegs.xxl.core.ISignalCommandMap;
	import org.robotlegs.xxl.core.ISignalMap;
	import org.swiftsuspenders.Reflector;
	
	/**
	 * ...
	 * @author XXL
	 */
	public class Context extends ContextBase implements IContext 
	{
		protected var _injector:IInjector;
		protected var _reflector:IReflector;
		
		protected var _signalCommandMap:ISignalCommandMap;
		protected var _mediatorMap:IMediatorMap;
		protected var _viewMap:IViewMap;
		protected var _signalMap:ISignalMap;
		
		protected var _contextView:DisplayObjectContainer;
		protected var _isDispose:Boolean = false;
		private var _autoStartup:Boolean;
		
		public function Context(contextView:DisplayObjectContainer = null,autoStartup:Boolean = true) 
		{
			super();
			
			_contextView = contextView;
			_autoStartup = autoStartup;
			
			signalMap.registerSignal(ContextSignal);
			
			if (_contextView)
			{
				mapInjections();
				checkAutoStartup();
			}
		}
		
		public function get contextView():DisplayObjectContainer 
		{
			return _contextView;
		}
		
		public function set contextView(value:DisplayObjectContainer):void 
		{
			if (value == _contextView)
			{
				return;
			}
			if (_contextView)
			{
				throw new ContextError(ContextError.E_CONTEXT_VIEW_OVR);
			}
			
			_contextView = value;
			mapInjections();
			checkAutoStartup();
		}
		
		protected function get injector():IInjector
		{
			if (_isDispose)
			{
				return _injector;
			}
			return _injector ||= createInjector();
		}
		
		protected function set injector(value:IInjector):void
		{
			this._injector = value;
		}
		
		protected function get reflector():IReflector 
		{
			if (_isDispose)
			{
				return _reflector;
			}
			return _reflector ||=new SwiftSuspendersReflector();
		}
		
		protected function set reflector(value:IReflector):void 
		{
			_reflector = value;
		}
		
		protected function get signalCommandMap():ISignalCommandMap 
		{
			if (_isDispose)
			{
				return _signalCommandMap;
			}
			return _signalCommandMap ||= new SignalCommandMap(injector, reflector, signalMap);
		}
		
		protected function set signalCommandMap(value:ISignalCommandMap):void 
		{
			_signalCommandMap = value;
		}
		
		protected function get mediatorMap():IMediatorMap 
		{
			if (_isDispose)
			{
				return _mediatorMap;
			}
			return _mediatorMap ||= new MediatorMap(contextView, createChildInjector(), reflector);
		}
		
		protected function set mediatorMap(value:IMediatorMap):void 
		{
			_mediatorMap = value;
		}
		
		protected function get viewMap():IViewMap 
		{
			if (_isDispose)
			{
				return _viewMap;
			}
			return _viewMap ||= new ViewMap(contextView, injector);
		}
		
		protected function set viewMap(value:IViewMap):void 
		{
			_viewMap = value;
		}
		
		public function get signalMap():ISignalMap 
		{
			if (_isDispose)
			{
				return _signalMap;
			}
			return _signalMap ||= new SignalMap(injector, reflector);
		}
		
		public function set signalMap(value:ISignalMap):void 
		{
			_signalMap = value;
		}
		
		protected function createInjector():IInjector 
		{
			var injector:IInjector = new SwiftSuspendersInjector();
			injector.applicationDomain = getApplicationDomainFromContextView();
			return injector;
		}
		
		protected function createChildInjector():IInjector
		{
			return injector.createChild(getApplicationDomainFromContextView());
		}
		
		protected function getApplicationDomainFromContextView():ApplicationDomain 
		{
			if (contextView && contextView.loaderInfo)
			{
				return contextView.loaderInfo.applicationDomain;
			}
			return ApplicationDomain.currentDomain;
		}
		
		protected function mapInjections():void 
		{
			injector.mapValue(IReflector, reflector);
			injector.mapValue(IInjector, injector);
			injector.mapValue(DisplayObjectContainer, contextView);
			injector.mapClass(ISignalMap, SignalMap);
			injector.mapValue(IMediatorMap, mediatorMap);
			injector.mapValue(IViewMap, viewMap);
			injector.mapValue(ISignalCommandMap, signalCommandMap);
		}
		
		//protected function unmapInjections():void
		//{
			//injector.unmap(IReflector);
			//injector.unmap(IInjector);
			//injector.unmap(DisplayObjectContainer);
			//injector.unmap(ISignalMap);
			//injector.unmap(IMediatorMap);
			//injector.unmap(IViewMap);
			//injector.unmap(ISignalCommandMap);
		//}
		
		protected var displayObjectSignalSet:DisplayObjectSignalSet;
		protected function checkAutoStartup():void
		{
			if (_autoStartup && contextView)
			{
				if (contextView.stage)
				{
					startup();
				}
				else
				{
					displayObjectSignalSet = new DisplayObjectSignalSet(contextView);
					displayObjectSignalSet.addedToStage.addOnce(function(e:Event):void{startup();});
				}
			}
		}
		
		public function startup():void 
		{
			(injector.getInstance(ContextSignal) as ISignal).dispatch(ContextSignal.STARTUP_COMPLETE, this);
		}
		
		public function shutdown():void
		{
			(injector.getInstance(ContextSignal) as ISignal).dispatch(ContextSignal.SHUTDOWN_COMPLETE, this);
		}
	}

}